<!DOCTYPE html><html class="appearance-auto" lang="zh-CN"><head><meta charset="UTF-8"><title>【Spring源码解析系列】 AOP源码解析</title><meta name="description" content="用创业者心态做好每一件事情！"><meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, initial-scale=1"><!-- Google Analytics --><!-- End Google Analytics -->
<!-- Baidu Analytics --><!-- End Baidu Analytics --><link rel="icon" href="/blog/images/favicon.png"><link rel="stylesheet" href="/blog/style/common/bulma.css"><link rel="stylesheet" href="/blog/style/base.css"><link rel="stylesheet" href="/blog/style/common/helper.css"><script src="/blog/js/common.js"></script><link rel="stylesheet" href="/blog/style/post.css"><link rel="stylesheet" href="/blog/style/themes/highlight-theme-light.css"><script src="/blog/js/highlight.pack.js"></script><meta name="description" content="
本文主要讲述Spring中AOP源码解析


Spring提供了两种方式来生成代理对象：JDKProxy和CGLIB，具体使用哪种方式生成由AopProxyFactory更加AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口，则使用JDK动态代理技术，否则使用CGLIB来上次代理；DefaultAopProxyFactory：createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException &amp;#123;
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUse.."><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/blog/atom.xml" title="janedler's blog" type="application/atom+xml">
</head><body class="is-flex is-flex-direction-column"><header class="header-widget is-flex-shrink-0 is-hidden-mobile"><div class="container is-fullhd is-flex is-justify-content-space-between is-align-items-center is-full-height"><section class="is-hidden-mobile is-flex-shrink-0"><h2><a href="/blog/">田园牧歌(*︶*)'s blog</a></h2></section><h3 class="is-hidden-mobile is-family-serif is-full-height is-flex is-align-items-center is-flex-shrink-0"><div class="is-full-height" id="postTopic"><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">【Spring源码解析系列】 AOP源码解析</p><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">点击返回顶部</p></div></h3><aside class="is-flex-shrink-0"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></aside></div></header><header class="is-flex header-widget is-flex-shrink-0 is-align-items-center is-justify-content-center is-hidden-tablet"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></header><main><main class="container is-max-widescreen content section post-page pt-4 px-4"><div class="columns is-flex-desktop is-justify-content-center is-flex-direction-row-reverse"><div class="column is-3 is-hidden-mobile is-hidden"></div><div class="column is-9"><header class="my-4"><a href="/blog/tags/Java"><i class="tag post-item-tag">Java</i></a><a href="/blog/tags/Spring"><i class="tag post-item-tag">Spring</i></a></header><h1 class="mt-0 mb-1 is-family-serif" id="postTitle">【Spring源码解析系列】 AOP源码解析</h1><time class="has-text-grey" datetime="2022-11-30T16:00:00.000Z">2022-12-01</time><article class="mt-2 post-content"><p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/spring.png" alt="cover"></p>
<p>本文主要讲述Spring中AOP源码解析</p>
<span id="more"></span>

<p>Spring提供了两种方式来生成代理对象：JDKProxy和CGLIB，具体使用哪种方式生成由AopProxyFactory更加AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口，则使用JDK动态代理技术，否则使用CGLIB来上次代理；<br>DefaultAopProxyFactory：createAopProxy</p>
<pre><code class="java">@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException &#123;
   if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) &#123;
      Class&lt;?&gt; targetClass = config.getTargetClass();
      if (targetClass == null) &#123;
         throw new AopConfigException(&quot;TargetSource cannot determine target class: &quot; +
               &quot;Either an interface or a target is required for proxy creation.&quot;);
      &#125;
      //如果有实现接口，默认实现JDK
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) &#123;
         return new JdkDynamicAopProxy(config);
      &#125;
      //否则就用CGLIB
      return new ObjenesisCglibAopProxy(config);
   &#125;
   else &#123;
      return new JdkDynamicAopProxy(config);
   &#125;
&#125;
</code></pre>
<p>以JDK动态代理为例</p>
<pre><code class="java">//获取代理类要实现的接口，除了Advised对象中配置的，还会加上SpringProxy，Advised(opaque=false)
//检查上面得到的接口中有没有定义equals或者hashcode的接口
//调用Proxy.newProxyInstance创建代理对象
@Override
public Object getProxy(@Nullable ClassLoader classLoader) &#123;
   if (logger.isTraceEnabled()) &#123;
      logger.trace(&quot;Creating JDK dynamic proxy: &quot; + this.advised.getTargetSource());
   &#125;
   return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
&#125;
</code></pre>
<p>代理对象生成了，那切面是如何织入的呢？<br>InvocationHandler是JDK动态代理的核心，生成的代理对象的方法调用会委托到InvocationHandler.invoke()方法。而通过JDKDynamicAopProxy的签名我们可以看到这个类其实也实现了InvocationHandler，下面我们通过分析这个类中实现的invoke方法来具体看下SpringAOP是如何织入切面的。</p>
<pre><code class="java">@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable &#123;
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try &#123;
      //equals()方法，具目标对象未实现此方法
      if (!this.equalsDefined &amp;&amp; AopUtils.isEqualsMethod(method)) &#123;
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      &#125;
      //hashCode()方法，具目标对象未实现此方法
      else if (!this.hashCodeDefined &amp;&amp; AopUtils.isHashCodeMethod(method)) &#123;
         // The target does not implement the hashCode() method itself.
         return hashCode();
      &#125;
      //Advised接口或者父接口中定义的方法，直接反射调用，不应通知
      else if (method.getDeclaringClass() == DecoratingProxy.class) &#123;
         // There is only getDecoratedClass() declared -&gt; dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      &#125;
      else if (!this.advised.opaque &amp;&amp; method.getDeclaringClass().isInterface() &amp;&amp;
            method.getDeclaringClass().isAssignableFrom(Advised.class)) &#123;
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      &#125;

      Object retVal;

      if (this.advised.exposeProxy) &#123;
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      &#125;

      // Get as late as possible to minimize the time we &quot;own&quot; the target,
      // in case it comes from a pool.
      //获取目标类
      target = targetSource.getTarget();
      Class&lt;?&gt; targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      //获取可以应用到此方法上的Interceptor列表
      //为环绕通知做准备
      List&lt;Object&gt; chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don&#39;t, we can fall back on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      //如果没有可以应用到此方法的通知(Interceptor)，此直接反射调用method.invoke(target,args)
      if (chain.isEmpty()) &#123;
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      &#125;
      else &#123;
         // We need to create a method invocation...
         //创建MethodInvocation
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      &#125;

      // Massage return value if necessary.
      Class&lt;?&gt; returnType = method.getReturnType();
      if (retVal != null &amp;&amp; retVal == target &amp;&amp;
            returnType != Object.class &amp;&amp; returnType.isInstance(proxy) &amp;&amp;
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) &#123;
         // Special case: it returned &quot;this&quot; and the return type of the method
         // is type-compatible. Note that we can&#39;t help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      &#125;
      else if (retVal == null &amp;&amp; returnType != Void.TYPE &amp;&amp; returnType.isPrimitive()) &#123;
         throw new AopInvocationException(
               &quot;Null return value from advice does not match primitive return type for: &quot; + method);
      &#125;
      return retVal;
   &#125;
   finally &#123;
      if (target != null &amp;&amp; !targetSource.isStatic()) &#123;
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      &#125;
      if (setProxyContext) &#123;
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      &#125;
   &#125;
&#125;
</code></pre>
<p>主流程可以简述为：获取可以应用到此方法上的通知链（Interceptor Chain），如果有，则应用通知，并执行joinpoint；如果没有，则直接反射执行joinPoint，而这里的关键是通知链是如何获取的以及它又是如何执行的，下面逐一分析下：<br>首先，从上面的代码可以看出，通知链是通过Advised.getInterceptorAndDynamicInterceptionAdvice()这个方法来获取的，我们来看下这个方法的实现：</p>
<pre><code class="java">//此Advisor能否应用到目标方法method上，将满足条件的Advisor通过AdvisorAdapter转化成Interceptor列表返回
@Override
public List&lt;Object&gt; getInterceptorsAndDynamicInterceptionAdvice(
      Advised config, Method method, @Nullable Class&lt;?&gt; targetClass) &#123;

   // This is somewhat tricky... We have to process introductions first,
   // but we need to preserve order in the ultimate list.
   //这里实际上注册一系列AdvisorAdapter，用于将Advisor转化成MethodInterceptor
   AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
   Advisor[] advisors = config.getAdvisors();
   List&lt;Object&gt; interceptorList = new ArrayList&lt;&gt;(advisors.length);
   Class&lt;?&gt; actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
   Boolean hasIntroductions = null;

   for (Advisor advisor : advisors) &#123;
      if (advisor instanceof PointcutAdvisor pointcutAdvisor) &#123;
         // Add it conditionally.
         if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) &#123;
            //检查当前advisor的pointcut是否可以匹配当前方法
            MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
            boolean match;
            if (mm instanceof IntroductionAwareMethodMatcher) &#123;
               if (hasIntroductions == null) &#123;
                  //查看是否包含IntroductionAdvisor
                  hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
               &#125;
               match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
            &#125;
            else &#123;
               match = mm.matches(method, actualClass);
            &#125;
            if (match) &#123;
               //将Advisor转化成Interceptor
               MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
               if (mm.isRuntime()) &#123;
                  // Creating a new object instance in the getInterceptors() method
                  // isn&#39;t a problem as we normally cache created chains.
                  for (MethodInterceptor interceptor : interceptors) &#123;
                     //切点，转换为MethodInterceptor，保存到一个容器里面，这个容器一定是一个链表，
                     //一定是顺序的。
                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                  &#125;
               &#125;
               else &#123;
                  interceptorList.addAll(Arrays.asList(interceptors));
               &#125;
            &#125;
         &#125;
      &#125;
      else if (advisor instanceof IntroductionAdvisor ia) &#123;
         if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) &#123;
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
         &#125;
      &#125;
      else &#123;
         Interceptor[] interceptors = registry.getInterceptors(advisor);
         interceptorList.addAll(Arrays.asList(interceptors));
      &#125;
   &#125;

   return interceptorList;
&#125;
</code></pre>
<p>执行完成后，Advised中配置能够应用到连接点或者目标类的Advisor全部被转化成了MethodInterceptor，接下来分析连接器链怎么起作用</p>
<pre><code class="java">invoke 
...代码省略...
// Check whether we have any advice. If we don&#39;t, we can fall back on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
//如果没有可以应用到此方法的通知(Interceptor)，此直接反射调用method.invoke(target,args)
if (chain.isEmpty()) &#123;
   // We can skip creating a MethodInvocation: just invoke the target directly
   // Note that the final invoker must be an InvokerInterceptor so we know it does
   // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
   Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
   retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
&#125;
else &#123;
   // We need to create a method invocation...
   //创建MethodInvocation
   MethodInvocation invocation =
         new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
   // Proceed to the joinpoint through the interceptor chain.
   retVal = invocation.proceed();
&#125;
</code></pre>
<p>从这段代码中可以看出，如果得到的拦截器链为空，则直接反射调用目标方法，否则创建MethodInvocation，调用其proceed方法，触发拦截器的执行</p>
<pre><code class="java">@Override
@Nullable
public Object proceed() throws Throwable &#123;
   // We start with an index of -1 and increment early.
   //如果Interceptor执行完了，则执行joinPoint
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) &#123;
      return invokeJoinpoint();
   &#125;

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   //如果要动态匹配joinPoint
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher dm) &#123;
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      Class&lt;?&gt; targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      //动态匹配，运行时参数是否满足匹配条件
      if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) &#123;
         //执行当前Interceptor
         return dm.interceptor.invoke(this);
      &#125;
      else &#123;
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         //动态匹配失败时，略过当前Interceptor，调用下一个Interceptor
         return proceed();
      &#125;
   &#125;
   else &#123;
      // It&#39;s an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      //执行当前Interceptor
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   &#125;
&#125;
</code></pre>
</article><section class="jump-container is-flex is-justify-content-space-between my-6"><!-- em is empty placeholder--><a class="button is-default" href="/blog/2022/12/01/Spring/Spring-Aware/" title="【Spring源码解析系列】 Aware"><i class="iconfont icon-prev mr-2 has-text-grey"></i><span class="has-text-weight-semibold">上一页: 【Spring源码解析系列】 Aware</span></a><a class="button is-default" href="/blog/2022/12/01/Spring/Spring-BeanDefinition/" title="【Spring源码解析系列】 BeanDefinition"><span class="has-text-weight-semibold">下一页: 【Spring源码解析系列】 BeanDefinition</span><i class="iconfont icon-next ml-2 has-text-grey"></i></a></section><article class="mt-6 comment-container"><script async repo="janedler/blog" src="https://utteranc.es/client.js" issue-term="pathname" theme="preferred-color-scheme"></script></article></div></div></main></main><footer class="is-flex is-flex-direction-column is-align-items-center is-flex-shrink-0 is-family-serif"><section class="sns-container"><!-- Github--><a title="github" target="_blank" rel="noopener nofollow" href="//github.com//janedler"><i class="iconfont icon-github"></i></a><!-- Ins--><!-- RSS--><a title="rss" target="_blank" rel="noopener nofollow" href="/blog/atom.xml"><i class="iconfont icon-rss"></i></a><!-- 知乎--><!-- 领英--><!-- 脸书--></section><p><span>Copyright ©</span><span> 田园牧歌(*︶*) 2022</span></p><div class="is-flex is-justify-content-center is-flex-wrap-wrap"><p>Powered by Hexo &verbar;&nbsp;</p><p class="is-flex is-justify-content-center"><a title="Hexo theme author" target="_blank" rel="noopener" href="//github.com/haojen">Theme by Haojen&nbsp;</a></p><div style="margin-top: 2px"><a class="github-button" title="github-button" target="_blank" rel="noopener" href="https://github.com/haojen/hexo-theme-Claudia" data-color-scheme="no-preference: light; light: light; dark: dark;" data-show-count="true"></a></div></div><div><span></span></div></footer><script async defer src="https://buttons.github.io/buttons.js"></script><script src="/blog/js/post.js"></script></body></html>